import cron from 'node-cron';
import { PrismaClient } from '@prisma/client';
import { Decimal } from '@prisma/client/runtime/library';
import { SinaStockAPI } from '../utils/SinaStockAPI';
import { EastMoneyAPI } from '../utils/EastMoneyAPI';

export class StockDataCrawler {
  private prisma: PrismaClient;
  private sinaAPI: SinaStockAPI;
  private eastMoneyAPI: EastMoneyAPI;
  private isRunning = false;
  private batchSize = 50; // 批量处理大小
  private delayBetweenBatches = 2000; // 批次间延迟(毫秒)

  constructor(config?: {
    batchSize?: number;
    delayBetweenBatches?: number;
  }) {
    this.prisma = new PrismaClient();
    this.sinaAPI = new SinaStockAPI();
    this.eastMoneyAPI = new EastMoneyAPI();
    
    if (config) {
      this.batchSize = config.batchSize || this.batchSize;
      this.delayBetweenBatches = config.delayBetweenBatches || this.delayBetweenBatches;
    }
  }

  /**
   * 启动定时任务
   */
  start() {
    console.log('🚀 启动股票数据爬虫定时任务');

    // 实时数据更新 - 交易时间内每30秒执行
    cron.schedule('*/30 * 9-15 * * 1-5', async () => {
      if (!this.isRunning) {
        console.log('⏰ 触发实时数据更新任务');
        await this.updateRealtimeData();
      } else {
        console.log('⚠️ 上一个任务仍在运行，跳过本次执行');
      }
    }, {
      timezone: "Asia/Shanghai"
    });

    // 历史数据补充 - 每天收盘后18:00执行
    cron.schedule('0 18 * * 1-5', async () => {
      console.log('⏰ 触发每日历史数据更新任务');
      await this.updateDailyData();
    }, {
      timezone: "Asia/Shanghai"
    });

    // 市场数据初始化 - 每天8:30执行一次
    cron.schedule('30 8 * * 1-5', async () => {
      console.log('⏰ 触发市场数据初始化任务');
      await this.initializeMarketData();
    }, {
      timezone: "Asia/Shanghai"
    });

    console.log('✅ 定时任务已启动');
  }

  /**
   * 更新实时数据
   */
  async updateRealtimeData() {
    if (this.isRunning) {
      console.warn('⚠️ 更新实时数据任务已在运行中，跳过本次执行');
      return;
    }
    
    this.isRunning = true;
    console.log('📊 开始更新实时股票数据...');

    try {
      // 获取所有活跃股票
      const stocks = await this.prisma.stock.findMany({
        where: { status: 1 },
        include: { market: true }
      });

      if (stocks.length === 0) {
        console.log('⚠️ 没有找到活跃股票');
        return;
      }

      console.log(`📋 共找到 ${stocks.length} 只活跃股票，开始分批处理...`);

      // 分批处理股票数据
      for (let i = 0; i < stocks.length; i += this.batchSize) {
        const batch = stocks.slice(i, i + this.batchSize);
        console.log(`📦 处理第 ${Math.floor(i / this.batchSize) + 1} 批，共 ${batch.length} 只股票`);
        
        // 按市场分组批量获取数据
        const marketGroups = this.groupStocksByMarket(batch);
        
        for (const [marketCode, stockList] of Object.entries(marketGroups)) {
          await this.updateMarketRealtimeData(marketCode, stockList);
          // 每个市场之间间隔1秒，避免API限制
          await this.sleep(1000);
        }

        // 批次间延迟
        if (i + this.batchSize < stocks.length) {
          await this.sleep(this.delayBetweenBatches);
        }
      }

      console.log(`✅ 实时数据更新完成，共处理 ${stocks.length} 只股票`);
    } catch (error: any) {
      console.error('❌ 更新实时数据失败:', error.message);
      throw error; // 重新抛出异常，让调用者知道任务失败
    } finally {
      this.isRunning = false;
      console.log('⏹️ 实时数据更新任务结束');
    }
  }

  /**
   * 更新每日历史数据
   */
  async updateDailyData() {
    console.log('📈 开始更新每日历史数据...');

    try {
      const today = new Date();
      today.setHours(0, 0, 0, 0);

      // 获取所有活跃股票
      const stocks = await this.prisma.stock.findMany({
        where: { status: 1 },
        include: { market: true }
      });

      let updatedCount = 0;
      let skippedCount = 0;

      console.log(`📋 共找到 ${stocks.length} 只活跃股票，开始处理每日历史数据...`);

      for (const stock of stocks) {
        // 检查今天的数据是否已存在
        const existingData = await this.prisma.stockDailyData.findFirst({
          where: {
            stockId: stock.id,
            tradeDate: today
          }
        });

        if (existingData) {
          skippedCount++;
          continue;
        }

        // 从实时数据表获取今日数据
        const realtimeData = await this.prisma.stockRealtime.findFirst({
          where: { stockId: stock.id }
        });

        if (realtimeData) {
          await this.prisma.stockDailyData.create({
            data: {
              stockId: stock.id,
              tradeDate: today,
              openPrice: realtimeData.openPrice || realtimeData.currentPrice,
              highPrice: realtimeData.highPrice || realtimeData.currentPrice,
              lowPrice: realtimeData.lowPrice || realtimeData.currentPrice,
              closePrice: realtimeData.currentPrice,
              volume: realtimeData.volume || BigInt(0),
              turnover: realtimeData.turnover || new Decimal(0),
              changeAmount: realtimeData.changeAmount || null,
              changePercent: realtimeData.changePercent || null
            }
          });
          
          updatedCount++;
        }

        // 每处理10只股票休息100毫秒
        if ((updatedCount + skippedCount) % 10 === 0) {
          await this.sleep(100);
        }
      }

      console.log(`✅ 每日数据更新完成，新增 ${updatedCount} 条记录，跳过 ${skippedCount} 条已存在记录`);
    } catch (error: any) {
      console.error('❌ 更新每日数据失败:', error.message);
      throw error; // 重新抛出异常，让调用者知道任务失败
    }
  }

  /**
   * 初始化市场数据
   */
  async initializeMarketData() {
    console.log('🌍 初始化市场数据...');

    try {
      // 确保所有市场都存在
      const markets = [
        { code: 'SH', name: '上海证券交易所', currency: 'CNY' },
        { code: 'SZ', name: '深圳证券交易所', currency: 'CNY' },
        { code: 'HK', name: '香港交易所', currency: 'HKD' },
        { code: 'US', name: '美国股市', currency: 'USD' },
        { code: 'UK', name: '英国股市', currency: 'GBP' },
        { code: 'NEEQ', name: '全国中小企业股份转让系统', currency: 'CNY' }
      ];

      let createdCount = 0;
      let updatedCount = 0;

      for (const market of markets) {
        // 先检查市场是否存在
        const existingMarket = await this.prisma.market.findFirst({
          where: { marketCode: market.code }
        });

        if (existingMarket) {
          // 市场已存在，更新（这里可以选择是否需要更新字段）
          await this.prisma.market.update({
            where: { marketCode: market.code },
            data: {
              marketName: market.name,
              currency: market.currency,
              tradingHours: {
                weekdays: "09:30-15:00",
                timezone: market.code.includes('SH') || market.code.includes('SZ') || market.code.includes('NEEQ') 
                  ? "Asia/Shanghai" : market.code === 'HK' ? "Asia/Hong_Kong" 
                  : market.code === 'US' ? "America/New_York" : "Europe/London"
              }
            }
          });
          updatedCount++;
        } else {
          // 创建新市场
          await this.prisma.market.create({
            data: {
              marketCode: market.code,
              marketName: market.name,
              currency: market.currency,
              tradingHours: {
                weekdays: "09:30-15:00",
                timezone: market.code.includes('SH') || market.code.includes('SZ') || market.code.includes('NEEQ') 
                  ? "Asia/Shanghai" : market.code === 'HK' ? "Asia/Hong_Kong" 
                  : market.code === 'US' ? "America/New_York" : "Europe/London"
              }
            }
          });
          createdCount++;
        }
      }

      console.log(`✅ 市场数据初始化完成，创建 ${createdCount} 个市场，更新 ${updatedCount} 个市场`);

      // 如果股票表为空，添加一些示例股票
      const stockCount = await this.prisma.stock.count();
      if (stockCount === 0) {
        console.log('📋 股票表为空，开始添加示例股票...');
        await this.addSampleStocks();
      } else {
        console.log(`📋 股票表已有 ${stockCount} 条记录，跳过示例股票添加`);
      }

      console.log('✅ 市场数据初始化完成');
    } catch (error: any) {
      console.error('❌ 初始化市场数据失败:', error.message);
      throw error; // 重新抛出异常，让调用者知道任务失败
    }
  }

  /**
   * 添加示例股票数据
   */
  private async addSampleStocks() {
    const sampleStocks = [
      // A股示例
      { code: '000001', name: '平安银行', marketCode: 'SZ' },
      { code: '000002', name: '万科A', marketCode: 'SZ' },
      { code: '600000', name: '浦发银行', marketCode: 'SH' },
      { code: '600036', name: '招商银行', marketCode: 'SH' },
      
      // 港股示例
      { code: '00700', name: '腾讯控股', marketCode: 'HK' },
      { code: '09988', name: '阿里巴巴-SW', marketCode: 'HK' },
      
      // 美股示例
      { code: 'AAPL', name: 'Apple Inc.', marketCode: 'US' },
      { code: 'MSFT', name: 'Microsoft Corporation', marketCode: 'US' }
    ];

    let addedCount = 0;

    for (const stock of sampleStocks) {
      try {
        const market = await this.prisma.market.findFirst({
          where: { marketCode: stock.marketCode }
        });

        if (market) {
          // 检查股票是否已存在
          const existingStock = await this.prisma.stock.findFirst({
            where: {
              stockCode: stock.code,
              marketId: market.id
            }
          });

          if (!existingStock) {
            await this.prisma.stock.create({
              data: {
                stockCode: stock.code,
                stockName: stock.name,
                marketId: market.id
              }
            });
            addedCount++;
          }
        }
      } catch (error: any) {
        console.error(`❌ 添加示例股票 ${stock.code} 失败:`, error.message);
      }
    }

    console.log(`✅ 成功添加了 ${addedCount} 只示例股票`);
  }

  /**
   * 从东方财富API批量导入A股股票数据
   */
  async importAllAStocks(): Promise<void> {
    console.log('🚀 开始从东方财富API批量导入A股股票数据...');

    try {
      // 获取所有A股数据 - 60页 × 100只/页 = 最多6000只股票
      const stocksData = await this.eastMoneyAPI.getAllAStocks(60);
      
      if (stocksData.length === 0) {
        console.log('⚠️ 未获取到任何股票数据');
        return;
      }

      console.log(`📋 共获取到 ${stocksData.length} 只股票，开始导入数据库...`);

      let addedCount = 0;
      let updatedCount = 0;
      let skippedCount = 0;

      // 确保市场数据存在
      await this.initializeMarketData();

      // 获取市场映射
      const markets = await this.prisma.market.findMany();
      const marketMap = new Map(markets.map(market => [market.marketCode, market]));

      // 分批处理股票数据
      for (let i = 0; i < stocksData.length; i += this.batchSize) {
        const batch = stocksData.slice(i, i + this.batchSize);
        console.log(`📦 处理第 ${Math.floor(i / this.batchSize) + 1} 批，共 ${batch.length} 只股票`);

        for (const stockData of batch) {
          try {
            const market = marketMap.get(stockData.marketCode);
            if (!market) {
              console.warn(`⚠️ 未找到市场: ${stockData.marketCode}，跳过股票: ${stockData.stockCode}`);
              skippedCount++;
              continue;
            }

            // 检查股票是否已存在
            const existingStock = await this.prisma.stock.findFirst({
              where: {
                stockCode: stockData.stockCode,
                marketId: market.id
              }
            });

            if (existingStock) {
              // 更新股票信息，包括板块分类
              await this.prisma.stock.update({
                where: { id: existingStock.id },
                data: {
                  stockName: stockData.stockName,
                  sector: stockData.sector, // 更新板块信息
                  updatedAt: new Date()
                }
              });
              updatedCount++;

              // 同时更新或创建实时数据
              await this.upsertRealtimeData(existingStock.id, stockData);
            } else {
              // 创建新股票，包括板块分类
              const newStock = await this.prisma.stock.create({
                data: {
                  stockCode: stockData.stockCode,
                  stockName: stockData.stockName,
                  sector: stockData.sector, // 设置板块信息
                  marketId: market.id
                }
              });
              addedCount++;

              // 创建实时数据
              await this.upsertRealtimeData(newStock.id, stockData);
            }
          } catch (error: any) {
            console.error(`❌ 处理股票 ${stockData.stockCode} 失败:`, error.message);
            skippedCount++;
          }
        }

        // 批次间延迟
        if (i + this.batchSize < stocksData.length) {
          await this.sleep(this.delayBetweenBatches);
        }
      }

      console.log(`✅ 股票数据导入完成! 新增: ${addedCount}, 更新: ${updatedCount}, 跳过: ${skippedCount}`);
    } catch (error: any) {
      console.error('❌ 批量导入股票数据失败:', error.message);
      throw error;
    }
  }

  /**
   * 安全地转换为Decimal类型
   */
  private safeDecimal(value: any, defaultValue: number = 0): Decimal | null {
    if (value === null || value === undefined || value === '' || value === '-') {
      return defaultValue === 0 ? new Decimal(0) : null;
    }
    
    const numValue = Number(value);
    if (isNaN(numValue) || !isFinite(numValue)) {
      return defaultValue === 0 ? new Decimal(0) : null;
    }
    
    try {
      return new Decimal(numValue);
    } catch (error) {
      console.warn(`转换Decimal失败: ${value}, 使用默认值: ${defaultValue}`);
      return defaultValue === 0 ? new Decimal(0) : null;
    }
  }

  /**
   * 更新或创建股票实时数据
   */
  private async upsertRealtimeData(stockId: number, stockData: any): Promise<void> {
    try {
      await this.prisma.stockRealtime.upsert({
        where: { stockId: stockId },
        update: {
          currentPrice: this.safeDecimal(stockData.currentPrice, 0)!,
          openPrice: this.safeDecimal(stockData.openPrice),
          closePrice: this.safeDecimal(stockData.closePrice),
          highPrice: this.safeDecimal(stockData.highPrice),
          lowPrice: this.safeDecimal(stockData.lowPrice),
          volume: stockData.volume || BigInt(0),
          turnover: this.safeDecimal(stockData.turnover),
          changeAmount: this.safeDecimal(stockData.changeAmount),
          changePercent: this.safeDecimal(stockData.changePercent),
          peRatio: this.safeDecimal(stockData.peRatio),
          pbRatio: this.safeDecimal(stockData.pbRatio),
          marketCap: this.safeDecimal(stockData.marketCap),
          updateTime: new Date()
        },
        create: {
          stockId: stockId,
          currentPrice: this.safeDecimal(stockData.currentPrice, 0)!,
          openPrice: this.safeDecimal(stockData.openPrice),
          closePrice: this.safeDecimal(stockData.closePrice),
          highPrice: this.safeDecimal(stockData.highPrice),
          lowPrice: this.safeDecimal(stockData.lowPrice),
          volume: stockData.volume || BigInt(0),
          turnover: this.safeDecimal(stockData.turnover),
          changeAmount: this.safeDecimal(stockData.changeAmount),
          changePercent: this.safeDecimal(stockData.changePercent),
          peRatio: this.safeDecimal(stockData.peRatio),
          pbRatio: this.safeDecimal(stockData.pbRatio),
          marketCap: this.safeDecimal(stockData.marketCap),
          updateTime: new Date()
        }
      });
    } catch (error: any) {
      console.error(`更新股票 ${stockId} 实时数据失败:`, error.message);
    }
  }

  /**
   * 按市场分组股票
   */
  private groupStocksByMarket(stocks: any[]) {
    const groups: { [key: string]: any[] } = {};
    
    stocks.forEach(stock => {
      const marketCode = stock.market.marketCode;
      if (!groups[marketCode]) {
        groups[marketCode] = [];
      }
      groups[marketCode].push(stock);
    });
    
    return groups;
  }

  /**
   * 更新特定市场的实时数据
   */
  private async updateMarketRealtimeData(marketCode: string, stocks: any[]) {
    try {
      console.log(`📊 开始更新 ${marketCode} 市场数据，共 ${stocks.length} 只股票...`);
      
      const stockData = stocks.map(stock => ({
        marketCode: stock.market.marketCode,
        stockCode: stock.stockCode
      }));

      const realtimeData = await this.sinaAPI.getBatchRealtimeData(stockData);
      
      let successCount = 0;
      let failCount = 0;

      for (let i = 0; i < realtimeData.length; i++) {
        const { stockCode, data } = realtimeData[i];
        const stock = stocks.find(s => s.stockCode === stockCode);
        
        if (stock && data) {
          try {
            await this.prisma.stockRealtime.upsert({
              where: { stockId: stock.id },
              update: {
                currentPrice: new Decimal(data.currentPrice),
                openPrice: data.openPrice ? new Decimal(data.openPrice) : null,
                closePrice: data.closePrice ? new Decimal(data.closePrice) : null,
                highPrice: data.highPrice ? new Decimal(data.highPrice) : null,
                lowPrice: data.lowPrice ? new Decimal(data.lowPrice) : null,
                volume: data.volume,
                turnover: data.turnover ? new Decimal(data.turnover) : null,
                changeAmount: data.changeAmount ? new Decimal(data.changeAmount) : null,
                changePercent: data.changePercent ? new Decimal(data.changePercent) : null,
                updateTime: new Date() // 更新时间戳
              },
              create: {
                stockId: stock.id,
                currentPrice: new Decimal(data.currentPrice),
                openPrice: data.openPrice ? new Decimal(data.openPrice) : null,
                closePrice: data.closePrice ? new Decimal(data.closePrice) : null,
                highPrice: data.highPrice ? new Decimal(data.highPrice) : null,
                lowPrice: data.lowPrice ? new Decimal(data.lowPrice) : null,
                volume: data.volume,
                turnover: data.turnover ? new Decimal(data.turnover) : null,
                changeAmount: data.changeAmount ? new Decimal(data.changeAmount) : null,
                changePercent: data.changePercent ? new Decimal(data.changePercent) : null,
                updateTime: new Date() // 创建时间戳
              }
            });
            successCount++;
          } catch (error: any) {
            console.error(`❌ 保存股票 ${stockCode} 数据失败:`, error.message);
            failCount++;
          }
        } else {
          failCount++;
        }
      }

      console.log(`📊 ${marketCode} 市场数据更新完成，成功 ${successCount} 只，失败 ${failCount} 只`);
    } catch (error: any) {
      console.error(`❌ 更新 ${marketCode} 市场数据失败:`, error.message);
      throw error; // 重新抛出异常，让调用者知道任务失败
    }
  }

  /**
   * 工具函数：延迟执行
   */
  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 停止定时任务
   */
  stop() {
    cron.getTasks().forEach(task => task.destroy());
    console.log('🛑 股票数据爬虫定时任务已停止');
  }
}
